gtk: Make GtkPointerFocus refcounted
authorCarlos Garnacho <carlosg@gnome.org>
Thu, 25 May 2017 14:00:40 +0000 (16:00 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Thu, 25 May 2017 14:25:59 +0000 (16:25 +0200)
In order to make it really sure the GtkPointerFocus is valid while being
removed from a GtkWindow.

gtk/gtkpointerfocus.c
gtk/gtkpointerfocusprivate.h
gtk/gtkwindow.c

index 3a4026d3d55e4d5973d9083fb8a4392b334666d9..cb484b8d343d3ff77f469526fdbe549431086ebb 100644 (file)
@@ -39,6 +39,7 @@ gtk_pointer_focus_new (GtkWindow        *toplevel,
   GtkPointerFocus *focus;
 
   focus = g_new0 (GtkPointerFocus, 1);
+  focus->ref_count = 1;
   focus->toplevel = toplevel;
   focus->device = device;
   focus->sequence = sequence;
@@ -48,12 +49,24 @@ gtk_pointer_focus_new (GtkWindow        *toplevel,
   return focus;
 }
 
+GtkPointerFocus *
+gtk_pointer_focus_ref (GtkPointerFocus *focus)
+{
+  focus->ref_count++;
+  return focus;
+}
+
 void
-gtk_pointer_focus_free (GtkPointerFocus *focus)
+gtk_pointer_focus_unref (GtkPointerFocus *focus)
 {
-  gtk_pointer_focus_set_target (focus, NULL);
-  gtk_pointer_focus_set_implicit_grab (focus, NULL);
-  g_free (focus);
+  focus->ref_count--;
+
+  if (focus->ref_count == 0)
+    {
+      gtk_pointer_focus_set_target (focus, NULL);
+      gtk_pointer_focus_set_implicit_grab (focus, NULL);
+      g_free (focus);
+    }
 }
 
 void
index 5d5be955e0fc8c1217ef98035f94020bfe44e80f..c7ffd90f979a4cf1b290ea1a903866e17670b94a 100644 (file)
@@ -24,6 +24,7 @@ typedef struct _GtkPointerFocus GtkPointerFocus;
 
 struct _GtkPointerFocus
 {
+  gint ref_count;
   GdkDevice *device;
   GdkEventSequence *sequence;
   GtkWindow *toplevel;
@@ -38,7 +39,8 @@ GtkPointerFocus * gtk_pointer_focus_new  (GtkWindow        *toplevel,
                                           GdkEventSequence *sequence,
                                           gdouble           x,
                                           gdouble           y);
-void              gtk_pointer_focus_free (GtkPointerFocus *focus);
+GtkPointerFocus * gtk_pointer_focus_ref   (GtkPointerFocus *focus);
+void              gtk_pointer_focus_unref (GtkPointerFocus *focus);
 
 void              gtk_pointer_focus_set_coordinates (GtkPointerFocus *focus,
                                                      gdouble          x,
index 03046731cb13b7a5b70117c2c795a6bdef59129a..8e711004bbc7c5ea4285affce7e5a61ab13514c0 100644 (file)
@@ -1689,9 +1689,9 @@ device_removed_cb (GdkSeat   *seat,
 
       if (focus->device == device)
         {
-          gtk_pointer_focus_free (focus);
           window->priv->foci =
             g_list_delete_link (window->priv->foci, cur);
+          gtk_pointer_focus_unref (focus);
         }
     }
 }
@@ -11275,7 +11275,7 @@ gtk_window_add_pointer_focus (GtkWindow       *window,
 {
   GtkWindowPrivate *priv = window->priv;
 
-  priv->foci = g_list_prepend (priv->foci, focus);
+  priv->foci = g_list_prepend (priv->foci, gtk_pointer_focus_ref (focus));
 }
 
 static void
@@ -11283,8 +11283,14 @@ gtk_window_remove_pointer_focus (GtkWindow       *window,
                                  GtkPointerFocus *focus)
 {
   GtkWindowPrivate *priv = window->priv;
+  GList *pos;
+
+  pos = g_list_find (priv->foci, focus);
+  if (!pos)
+    return;
 
   priv->foci = g_list_remove (priv->foci, focus);
+  gtk_pointer_focus_unref (focus);
 }
 
 static GtkPointerFocus *
@@ -11351,6 +11357,8 @@ gtk_window_update_pointer_focus (GtkWindow        *window,
   focus = gtk_window_lookup_pointer_focus (window, device, sequence);
   if (focus)
     {
+      gtk_pointer_focus_ref (focus);
+
       if (target)
         {
           gtk_pointer_focus_set_target (focus, target);
@@ -11359,8 +11367,9 @@ gtk_window_update_pointer_focus (GtkWindow        *window,
       else
         {
           gtk_window_remove_pointer_focus (window, focus);
-          gtk_pointer_focus_free (focus);
         }
+
+      gtk_pointer_focus_unref (focus);
     }
   else if (target)
     {
@@ -11383,17 +11392,20 @@ gtk_window_update_pointer_focus_on_state_change (GtkWindow *window,
       focus = cur->data;
       l = cur->next;
 
+      gtk_pointer_focus_ref (focus);
+
       if (GTK_WIDGET (focus->toplevel) == widget)
         {
           /* Unmapping the toplevel, remove pointer focus */
           gtk_window_remove_pointer_focus (window, focus);
-          gtk_pointer_focus_free (focus);
         }
       else if (focus->target == widget ||
                gtk_widget_is_ancestor (focus->target, widget))
         {
           gtk_pointer_focus_repick_target (focus);
         }
+
+      gtk_pointer_focus_unref (focus);
     }
 }